/* 
 * Copyright 2010-2011 Johannes Tuikkala <johannes.tuikkala@itmill.com>
 * 
 * Licensed under the Apache License, Version 2.0 (the "License"); you may not
 * use this file except in compliance with the License. You may obtain a copy of
 * the License at
 * 
 * http://www.apache.org/licenses/LICENSE-2.0
 * 
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
 * License for the specific language governing permissions and limitations under
 * the License.
 */
package org.vaadin.webcamforvaadin;

import java.io.ByteArrayInputStream;
import java.io.InputStream;
import java.util.Map;

import org.vaadin.webcamforvaadin.gwt.client.ui.VWebCamForVaadin;

import com.vaadin.terminal.PaintException;
import com.vaadin.terminal.PaintTarget;
import com.vaadin.terminal.StreamResource;
import com.vaadin.ui.AbstractComponent;
import com.vaadin.ui.ClientWidget;

@ClientWidget(VWebCamForVaadin.class)
public class WebCamForVaadin extends AbstractComponent {
	private static final long serialVersionUID = 6812732529966914209L;
	/** start the capture of single image */
	private boolean captureNow = false;
	/** width of the webcam image */
	private int webcamWidth = 640;
	/** height of the webcam image */
	private int webcamHeight = 480;
	/** WebCamListener for image ready and error handling */
	private WebCamListener listener;

	/**
	 * delay in millis between captured frames, iff frameDelay=0, then network
	 * and cpu is only limiting factor on framerate
	 */
	private int frameDelay = 1000;
	private Thread captureThread;
	private boolean autoCapturing = false;

	private final WebCamStreamVariable imageVar;

	/**
	 * Construct default webcam component
	 */
	public WebCamForVaadin(WebCamListener listener) {
		super();
		imageVar = new WebCamStreamVariable(this);
		setImmediate(true);
		this.setDebugId("VAADIN_WEBCAM_PID");
		this.listener = listener;
		setWidth("1px");
		setHeight("1px");
	}

	@Override
	public synchronized void changeVariables(Object source,
			Map<String, Object> variables) {
		super.changeVariables(source, variables);
		if (variables.containsKey("errormessage")) {
			listener.onError((String) variables.get("errormessage"));
		}
	}

	/**
	 * Fire onImageReady listener
	 */
	public void imageReady() {
		listener.onImageReady();
	}

	/**
	 * Do the capture
	 */
	public synchronized void capture() {
		captureNow = true;
		requestRepaint();
	}

	/**
	 * Returns the captured image as a StreamResource
	 * 
	 * @return
	 */
	public synchronized StreamResource getPicture() {
		return new StreamResource(new StreamResource.StreamSource() {
			private static final long serialVersionUID = -1453924172623193241L;

			public InputStream getStream() {
				return new ByteArrayInputStream(imageVar.baos.toByteArray());
			}
		}, "webcamimagedata", this.getApplication());
	}

	/**
	 * Paints the uidl
	 * 
	 * @param PaintTarget
	 *            target
	 * @throws PaintException
	 */
	@Override
	public synchronized void paintContent(PaintTarget target)
			throws PaintException {
		// Superclass writes any common attributes in the paint target.
		super.paintContent(target);
		target.addAttribute("capturenow", captureNow);
		target.addAttribute("webcamWidth", webcamWidth);
		target.addAttribute("webcamHeight", webcamHeight);
		target.addAttribute("frameDelay", getFrameDelay());
		target.addVariable(this, "postTargetUri", imageVar);
	}

	/**
	 * Returns width of the webcam image
	 * 
	 * @return
	 */
	public int getWebCamWidth() {
		return webcamWidth;
	}

	/**
	 * Returns height of the webcam image
	 * 
	 * @return
	 */
	public int getWebCamHeight() {
		return webcamHeight;
	}

	/**
	 * Sets delay in millis between captured frames,<br />
	 * iff frameDelay=0, then network and cpu is only limiting factor on
	 * framerate
	 */
	public void setFrameDelay(int frameDelay) {
		this.frameDelay = frameDelay;
	}

	/**
	 * Gets delay in millis between captured frames,<br />
	 * iff frameDelay=0, then network and cpu is only limiting factor on
	 * framerate
	 */
	public int getFrameDelay() {
		return frameDelay;
	}

	public void startAutoCapture() {
		autoCapturing = true;
		captureThread = new Thread() {
			@Override
			public void run() {
				while (autoCapturing) {
					try {
						Thread.sleep(frameDelay);
					} catch (InterruptedException e) {
					}
					capture();
				}
			}
		};
		captureThread.start();
	}

	public void stopAutoCapture() {
		autoCapturing = false;
	}

	public void setWebCamWidthAndHeight(int width, int height) {
		this.webcamWidth = width;
		this.webcamHeight = height;
		requestRepaint();
	}
}
